home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The X-Philes (2nd Revision)
/
The X-Philes Number 1 (1995).iso
/
xphiles
/
hp48hor2
/
tasc8.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-02-18
|
9KB
|
315 lines
/* tasc (version 3): ASC-encoder/decoder for HP48 files
Copyright 1992 by Jonathan T. Higa
Credits:
- ASC: Bill Wickes (billw@hpcvdw.cv.hp.com).
- Cyclic Redundancy Check:
da Cruz, Frank. _Kermit: A File Transfer Protocol._
Bedford, MA: Digital Press, 1987.
- Object structure:
HP48 Tools Manual;
"HP48SX Internals," by Derek S. Nickel.
- Guidance: Joe Horn (akcs.joehorn@hpcvbbs.cv.hp.com)
- Original inspiration:
miscellaneous asc2bin programs on seq.uncwil.edu
*/
#include <stdio.h>
#include <string.h>
struct hexbuf {
unsigned long bits;
long nibs;
int bsize;
unsigned short crc;
};
enum hpdatatype { HPBIN, HPASC, UNKNOWN = -1 };
int verbose = 1;
void pushhex(struct hexbuf *b, int h)
/* Add a hex digit to the bit buffer. */
{
b->bits |= (h & 0xfuL) << b->bsize;
b->bsize += 4;
}
int pophex(struct hexbuf *b)
/* Remove and return a hex digit from the bit buffer, and
include it in the CRC. */
{
int h = b->bits & 0xf;
b->crc = (b->crc >> 4) ^ (((b->crc ^ h) & 0xf) * 0x1081);
b->nibs++;
b->bits >>= 4;
b->bsize -= 4;
return h;
}
enum hpdatatype hptype(FILE *f)
/* Determine the type of HP file by scanning the beginning of the file.
If the type is known, put the file pointer at the start of data. */
{
char c;
if (fscanf(f, "HPHP48-%c", &c) == 1)
return HPBIN;
else
for (; ; )
switch (fscanf(f, "%*[%]HP:%*[^;]%c", &c)) {
case 1:
while (fscanf(f, " @%c", &c) == 1) {
if (c != '\n') {
fscanf(f, "%*[^\n]");
fscanf(f, "%*1[\n]");
}
}
return fscanf(f, "%c", &c) == 1 && c == '"' ? HPASC : UNKNOWN;
case 0:
fscanf(f, "%*[^\n]");
fscanf(f, "%*1[\n]");
break;
case EOF:
return UNKNOWN;
}
}
char *newext(char *new, const char *old, const char *ext)
/* Create a new filename from the old filename and extension. */
{
char *p = strrchr(strcpy(new, old), ext[0]);
if (p) strcpy(p, ext);
else strcat(new, ext);
if (verbose) fprintf(stderr, "tasc: inventing filename \"%s\"\n", new);
return new;
}
int asctobin(FILE *fasc, FILE *fbin)
{
struct hexbuf hb = {0, 0, 0, 0};
int d;
/* write header into binary file */
fputs("HPHP48-E", fbin);
/* translate data */
while (fscanf(fasc, "%1x", &d) == 1) {
pushhex(&hb, d);
if (hb.bsize >= 24) {
d = pophex(&hb);
d |= pophex(&hb) << 4;
putc(d, fbin);
}
}
if (hb.bsize > 16) {
d = pophex(&hb);
putc(d, fbin);
}
/* check CRC */
if (hb.crc != hb.bits || hb.bsize != 16) {
fprintf(stderr, "tasc: ASC->bin: CRC is incorrect\n");
return 1;
}
if (verbose)
fprintf(stderr, "tasc: ASC->bin: BYTES: #%hXh %ld%s\n",
hb.crc, hb.nibs/2, hb.nibs & 1 ? ".5" : "");
return 0;
}
int bintoasc(FILE *fbin, FILE *fasc)
{
struct hexbuf hb = {0, 0, 0, 0};
unsigned long fldlen = 0;
enum { SIZE, ASCIC, ASCIX, DIR, ANY = -1 } fldnxt = ANY;
int c, width = 0;
/* write header into ASC file */
fprintf(fasc, "%%%%HP: T(1);\n\"");
/* parse binary */
while ((c = getc(fbin)) != EOF) {
pushhex(&hb, c);
pushhex(&hb, c >> 4);
if (!fldlen) /* done with previous field */
switch (fldnxt) { /* now for the current field */
case SIZE:
if (hb.bsize >= 20) {
/* this object's length is known by the size field */
fldlen = hb.bits & 0xfffff;
fldnxt = ANY;
}
break;
case ASCIC:
if (hb.bsize >= 8) {
/* ASCII-char identifier */
fldlen = 2 + 2 * (hb.bits & 0xff);
fldnxt = ANY;
}
break;
case ASCIX:
if (hb.bsize >= 8) {
/* ASCII-extended identifier */
fldlen = 4 + 2 * (hb.bits & 0xff);
fldnxt = ANY;
}
break;
case DIR:
if (hb.bsize >= 20) {
/* first object pointer in a directory, to an ASCIX name */
fldlen = hb.bits & 0xfffff;
fldnxt = ASCIX;
}
break;
default:
if (hb.bsize >= 20) {
unsigned long pro = hb.bits & 0xfffff;
fldlen = 5; /* the prolog field is 5 nibbles long */
if (pro == 0x29e8uL || pro == 0x2a0auL || pro == 0x2a2cuL
|| pro == 0x2a4euL || pro == 0x2b1euL || pro == 0x2b40uL
|| pro == 0x2b62uL || pro == 0x2b88uL || pro == 0x2dccuL)
fldnxt = SIZE; /* expect a size field */
else if (pro == 0x2e48uL || pro == 0x2e6duL || pro == 0x2afcuL)
fldnxt = ASCIC; /* expect an ASCIC object */
else if (pro == 0x2a96uL) {
/* expect the directory pointer after the first 8 nibbles */
fldlen = 8;
fldnxt = DIR;
}
else if (pro == 0x2911uL) fldlen = 10; /* is system binary */
else if (pro == 0x2933uL) fldlen = 21; /* is real */
else if (pro == 0x2955uL) fldlen = 26; /* is long real */
else if (pro == 0x2977uL) fldlen = 37; /* is complex */
else if (pro == 0x299duL) fldlen = 47; /* is long complex */
else if (pro == 0x29bfuL) fldlen = 7; /* is char */
else if (pro == 0x2e92uL) fldlen = 11; /* is XLIB name */
}
break;
}
/* write out the current field */
while (fldlen && hb.bsize) {
c = pophex(&hb);
if (width == 64) {
putc('\n', fasc);
width = 0;
}
fprintf(fasc, "%X", c);
width++;
fldlen--;
}
}
if (hb.bits) {
fprintf(stderr, "tasc: bin->ASC: end of last object not found\n");
return 1;
}
/* append CRC */
if (verbose)
fprintf(stderr, "tasc: bin->ASC: BYTES: #%hXh %ld%s\n",
hb.crc, hb.nibs / 2, hb.nibs & 1 ? ".5" : "");
hb.bits = hb.crc;
hb.bsize = 16;
while (hb.bsize) {
if (width == 64) {
putc('\n', fasc);
width = 0;
}
fprintf(fasc, "%X", pophex(&hb));
width++;
}
fprintf(fasc, "\"\n");
return 0;
}
int main(int argc, char **argv)
{
const char *STDIO = "-";
enum hpdatatype coding = UNKNOWN;
int i = 1;
char *iname, *oname, temp[256];
if (argc > i && argv[i][0] == '-') {
switch (argv[i][1]) {
case 'd':
coding = HPASC;
i++;
break;
case 'e':
coding = HPBIN;
i++;
break;
case 'q':
verbose = 0;
i++;
break;
}
}
argc -= i;
if (argc < 1 || argc > 2) {
fprintf(stderr, "Use: %s [opt ...] source [target]\n"
"opt\taction\n"
" -d\tForce ASC->bin (ASC decode)\n"
" -e\tForce bin->ASC (ASC encode)\n"
" -q\tSuppress non-error messages (quiet)\n"
"The filename \"-\" represents the terminal.\n",
argv[0]);
return 1;
}
iname = argv[i];
if (strcmp(iname, STDIO)) {
if (!freopen(iname, "rb", stdin)) {
fprintf(stderr, "tasc: ");
perror(iname);
return 1;
}
} else if (argc == 1) {
fprintf(stderr, "tasc: cannot invent output filename for stdin\n");
return 1;
}
switch (hptype(stdin)) {
case HPASC:
if (coding == HPBIN) {
fprintf(stderr, "tasc: ASC->bin mode was disallowed\n");
return 1;
}
if (verbose) fprintf(stderr, "tasc: entering ASC->bin mode\n");
oname = argc == 1 ? newext(temp, iname, ".bin") : argv[i+1];
if (strcmp(oname, STDIO) && !freopen(oname, "wb", stdout)) {
fprintf(stderr, "tasc: ");
perror(oname);
return 1;
}
if (asctobin(stdin, stdout))
return 1;
break;
case HPBIN:
if (coding == HPASC) {
fprintf(stderr, "tasc: bin->ASC mode was disallowed\n");
return 1;
}
if (verbose) fprintf(stderr, "tasc: entering bin->ASC mode\n");
oname = argc == 1 ? newext(temp, iname, ".asc") : argv[i+1];
if (strcmp(oname, STDIO) && !freopen(oname, "w", stdout)) {
fprintf(stderr, "tasc: ");
perror(oname);
return 1;
}
if (bintoasc(stdin, stdout))
return 1;
break;
default:
fprintf(stderr, "tasc: unknown input type\n");
return 1;
}
if (fclose(stdin)) {
fprintf(stderr, "tasc: ");
perror(iname);
return 1;
}
if (fclose(stdout)) {
fprintf(stderr, "tasc: ");
perror(oname);
return 1;
}
return 0;
}